package net.srcz.android.screencast.api.injector;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Date;

import javax.swing.SwingUtilities;

import org.omg.CORBA.ByteHolder;

import net.srcz.android.screencast.api.AndroidDevice;
import net.srcz.android.screencast.api.recording.QuickTimeOutputStream;

import com.android.ddmlib.IDevice;
import com.android.ddmlib.RawImage;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;

public class ScreenCaptureThread extends Thread {

	private BufferedImage image;
	private Dimension size;
	private IDevice device;
	private QuickTimeOutputStream qos = null;
	private boolean landscape = false;
	private ScreenCaptureListener listener = null;

	public ScreenCaptureListener getListener() {
		return listener;
	}

	public void setListener(ScreenCaptureListener listener) {
		this.listener = listener;
	}

	public interface ScreenCaptureListener {
		public void handleNewImage(Dimension size, BufferedImage image,
				boolean landscape);
	}

	public ScreenCaptureThread(IDevice device) {
		super("Screen capture");
		this.device = device;
		image = null;
		size = new Dimension();
	}

	public Dimension getPreferredSize() {
		return size;
	}

	public void run() {
		try {
			server = new Socket("127.0.0.1", 5678);
			DataInputStream in = new DataInputStream(new BufferedInputStream(
					server.getInputStream(), 1024));
			PrintWriter out = new PrintWriter(server.getOutputStream());

			do {
				try {
					boolean ok = fetchImage(in, out);
					if (!ok)
						break;
				} catch (java.nio.channels.ClosedByInterruptException ciex) {
					break;
				} catch (IOException e) {
					System.err.println((new StringBuilder())
							.append("Exception fetching image: ")
							.append(e.toString()).toString());
				}

			} while (true);

			server.close();
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}

	public void startRecording(File f) {
		try {
			if (!f.getName().toLowerCase().endsWith(".mov"))
				f = new File(f.getAbsolutePath() + ".mov");
			qos = new QuickTimeOutputStream(f,
					QuickTimeOutputStream.VideoFormat.JPG);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		qos.setVideoCompressionQuality(1f);
		qos.setTimeScale(30); // 30 fps
	}

	public void stopRecording() {
		try {
			QuickTimeOutputStream o = qos;
			qos = null;
			o.close();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	static Socket server;
	static byte[] by = new byte[1024];
	static byte[] memory = new byte[30000];
	static long start=0;
	static long middle=0;
	static long end=0;

	private boolean fetchImage(DataInputStream in, PrintWriter out)
			throws IOException {
		if (device == null) {
			// device not ready
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				return false;
			}
			return true;
		}

		// RawImage rawImage = null;
		BufferedImage image;
		synchronized (device) {
			// String filename = "d:/1.jpg";

			// File f = new File(filename);
			// AndroidDevice d = new AndroidDevice(device);
			// System.out.println(d.executeCommand("/data/local/gsnap /sdcard/test/2.jpg /dev/graphics/fb0 50"));
			// d.pullFile("/sdcard/test/2.jpg", f);

			// String cmd =
			// "adb shell /data/local/gsnap /sdcard/test/2.jpg /dev/graphics/fb0 75 2";
			// runCmd(cmd);
			// cmd = "adb pull /sdcard/test/2.jpg d:/1.jpg";
			// runCmd(cmd);
			start = System.currentTimeMillis();
			System.out.println("third:\t\t\t"+String.valueOf(start - end));
			
			out.println("snap");
			out.flush();

			for (int i = 0;;) {
				int read = in.read(by);
				for (byte b : by) {
					memory[i] = b;
					i++;
				}
				if (read != 1024) {
					break;
				}
			}
			middle = System.currentTimeMillis();
			ByteArrayInputStream bas = new ByteArrayInputStream(memory);

			JPEGImageDecoder jpeg_decode = JPEGCodec.createJPEGDecoder(bas);
			image = jpeg_decode.decodeAsBufferedImage();
			end =  System.currentTimeMillis();
			System.out.println("first:\t"+String.valueOf(middle - start));
			System.out.println("second:\t\t"+String.valueOf(end - middle));
			// rawImage = device.getScreenshot();
			// System.out.println("Time now: \t" + System.currentTimeMillis());
		}
		if (image != null) {
			display(image);
		} else {
			System.out.println("failed getting screenshot through ADB ok");
		}
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			return false;
		}

		return true;
	}

	private void runCmd(String cmd) {
		Process p;
		try {
			p = Runtime.getRuntime().exec(cmd);
			p.waitFor();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void toogleOrientation() {
		landscape = !landscape;
	}

	public void display(BufferedImage bufferImage) {
		image = bufferImage;
		size.setSize(image.getWidth(), image.getHeight());
		landscape = false;

		try {
			if (qos != null)
				qos.writeFrame(image, 10);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		if (listener != null) {
			SwingUtilities.invokeLater(new Runnable() {

				public void run() {
					listener.handleNewImage(size, image, landscape);
					// jp.handleNewImage(size, image, landscape);
				}
			});
		}

	}

	public void display(RawImage rawImage) {
		int width2 = landscape ? rawImage.height : rawImage.width;
		int height2 = landscape ? rawImage.width : rawImage.height;
		if (image == null) {
			image = new BufferedImage(width2, height2,
					BufferedImage.TYPE_INT_RGB);
			size.setSize(image.getWidth(), image.getHeight());
		} else {
			if (image.getHeight() != height2 || image.getWidth() != width2) {
				image = new BufferedImage(width2, height2,
						BufferedImage.TYPE_INT_RGB);
				size.setSize(image.getWidth(), image.getHeight());
			}
		}
		int index = 0;
		int indexInc = rawImage.bpp >> 3;
		for (int y = 0; y < rawImage.height; y++) {
			for (int x = 0; x < rawImage.width; x++, index += indexInc) {
				int value = rawImage.getARGB(index);
				if (landscape)
					image.setRGB(y, rawImage.width - x - 1, value);
				else
					image.setRGB(x, y, value);
			}
		}

		try {
			if (qos != null)
				qos.writeFrame(image, 10);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		if (listener != null) {
			SwingUtilities.invokeLater(new Runnable() {

				public void run() {
					listener.handleNewImage(size, image, landscape);
					// jp.handleNewImage(size, image, landscape);
				}
			});
		}
	}

}
